import { CurrentInstance } from './instance'
import { mitt, Emitter } from './event'
import { isFunction, isObject } from './utils'
import { deepToRaw } from './shared'
import { effect } from './reactive'
import { diff } from './diff'

export type IContext = {
	setData: (params: Record<string, any>) => void,
	event: Emitter
}

/** 
 * 创建context对象
 * @param target {CurrentInstance} 小程序 this 实例
 * @return {IContext} context 对象
 */
export function createContext(this: CurrentInstance): IContext {
	// 封装setData方法
	function setData(this: CurrentInstance, binding: Record<string, any>): void {
		if (!binding) return

		Object.keys(binding).map(key => {
			const value = binding[key]
			if (isFunction(value)) return this[key] = value

			_setData.call(this, key, deepToRaw(value))
			// 添加监听
			dataWatch.call(this, key, value)
		})
	}

	return {
		setData: setData.bind(this),
		event: mitt()
	}
}

/** 
 * 添加data监听
 * @param key {String} 键值
 * @param value {unknown} 值
 */
function dataWatch(this: CurrentInstance, key: string, value: unknown) {
	// 非对象不监听
	if (!isObject(value)) return

	// 添加监听
	effect(() => {
		_setData.call(this, key, deepToRaw(value))
	}, true)
}

let hasPromise = new Map(); // 当前任务列队是有已有Promise
let allData = new Map() // 所有setData的值
/** 
 * 修改data值
 * @param data {Object} 要更新的值
 */
export function _setData(this: CurrentInstance, key: string, data: object) {
	let _allData = allData.get(this) || {}
	let _data = diff({ [key]: data }, { [key]: this.data[key] })
	for (let k in _data) {
        for (let j in _allData) {
			new RegExp('^'+k+'\\[\\d+\\].*$').test(j) && delete _allData[j]
        }
    }
	allData.set(this,
		Object.assign(_allData, _data)
	)
	if (!hasPromise.get(this)) {
		hasPromise.set(this, true)
		Promise.resolve().then(() => {
			(Object.getOwnPropertyNames(allData.get(this)).length !== 0)
				&& this.setData(allData.get(this))
			allData.delete(this);
			hasPromise.delete(this);
		})
	}
}
